/**
 * 认证控制器类
 * 
 * 功能说明：
 * - 提供RESTful API接口处理用户认证相关请求
 * - 包含登录、注册、令牌刷新、注销、密码修改、用户信息更新等功能
 * - 使用Swagger注解提供API文档
 * - 统一返回ResponseEntity包装响应数据
 * 
 * API设计规范：
 * - 所有接口统一使用/api/auth前缀
 * - POST方法用于创建资源（登录、注册）
 * - PUT方法用于更新资源（修改密码、更新信息）
 * - 使用@Valid注解进行参数校验
 * - 统一返回200状态码，错误信息包含在响应体中
 * 
 * 安全考虑：
 * - 登录和注册接口无需认证
 * - 其他接口需要在请求头中携带有效的JWT令牌
 * - 令牌格式：Authorization: Bearer {token}
 * 
 * @author eCommerce Team
 * @version 1.0
 */
package com.ecommerce.auth.controller;

import com.ecommerce.auth.dto.AuthResponse;
import com.ecommerce.auth.dto.ChangePasswordRequest;
import com.ecommerce.auth.dto.LoginRequest;
import com.ecommerce.auth.dto.RegisterRequest;
import com.ecommerce.auth.dto.ServiceLoginRequest;
import com.ecommerce.auth.dto.ServiceLoginResponse;
import com.ecommerce.auth.dto.UpdateProfileRequest;
import com.ecommerce.auth.dto.UserInfoResponse;
import com.ecommerce.auth.service.AuthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.List;

/**
 * 认证控制器
 * 处理所有用户认证相关的HTTP请求
 */
@RestController
@RequestMapping("/api/auth")
@Tag(name = "认证管理", description = "用户认证相关接口")
public class AuthController {

    /**
     * 认证服务接口
     * 通过构造器注入，确保依赖不为null
     */
    private final AuthService authService;

    /**
     * 构造方法
     * 
     * 使用构造器注入认证服务，符合Spring官方推荐做法
     * 优势：
     * - 保证依赖注入的完整性
     * - 便于单元测试时注入mock对象
     * - 提高代码的可读性和可维护性
     * 
     * @param authService 认证服务实现类
     */
    @Autowired
    public AuthController(AuthService authService) {
        this.authService = authService;
    }

    /**
     * 用户登录接口
     * 
     * 接口说明：
     * - 接收JSON格式的登录请求体
     * - 使用@Valid注解进行参数校验
     * - 调用认证服务进行业务处理
     * - 返回包含JWT令牌的认证响应
     * 
     * 请求示例：
     * POST /api/auth/login
     * Content-Type: application/json
     * {
     *   "username": "user123",
     *   "password": "password123"
     * }
     * 
     * 响应示例：
     * {
     *   "token": "eyJhbGciOiJIUzI1NiJ9...",
     *   "refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
     *   "userId": 1,
     *   "username": "user123",
     *   ...
     * }
     * 
     * @param loginRequest 登录请求对象，包含用户名和密码
     * @return ResponseEntity包装的认证响应，包含JWT令牌和用户信息
     */
    @PostMapping("/login")
    @Operation(summary = "用户登录", description = "用户使用用户名和密码登录系统")
    public ResponseEntity<AuthResponse> login(@Valid @RequestBody LoginRequest loginRequest) {
        AuthResponse authResponse = authService.login(loginRequest);
        return ResponseEntity.ok(authResponse);
    }

    /**
     * 用户注册接口
     * 
     * 接口说明：
     * - 接收JSON格式的注册请求体
     * - 使用@Valid注解进行参数校验
     * - 调用认证服务进行用户注册业务处理
     * - 注册成功后自动登录并返回JWT令牌
     * 
     * 注册流程：
     * 1. 验证注册信息的完整性和格式
     * 2. 检查用户名是否已存在
     * 3. 使用BCrypt加密用户密码
     * 4. 创建用户记录并保存到数据库
     * 5. 生成JWT访问令牌和刷新令牌
     * 
     * 数据验证：
     * - 用户名：必填，长度3-20位，支持字母数字下划线
     * - 密码：必填，长度6-20位，需包含字母和数字
     * - 邮箱：可选，需符合邮箱格式
     * - 手机号：可选，需符合手机号格式
     * 
     * 请求示例：
     * POST /api/auth/register
     * Content-Type: application/json
     * {
     *   "username": "newuser123",
     *   "password": "password123",
     *   "confirmPassword": "password123",
     *   "email": "user@example.com",
     *   "phoneNumber": "13800138000"
     * }
     * 
     * 响应示例：
     * {
     *   "token": "eyJhbGciOiJIUzI1NiJ9...",
     *   "refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
     *   "userId": 123,
     *   "username": "newuser123",
     *   "message": "注册成功"
     * }
     * 
     * 错误处理：
     * - 用户名已存在：返回400错误
     * - 密码不一致：返回400错误
     * - 参数验证失败：返回400错误
     * 
     * @param registerRequest 注册请求对象，包含用户注册信息
     * @return ResponseEntity包装的认证响应，包含JWT令牌和用户信息
     */
    @PostMapping("/register")
    @Operation(summary = "用户注册", description = "新用户注册")
    public ResponseEntity<AuthResponse> register(@Valid @RequestBody RegisterRequest registerRequest) {
        AuthResponse authResponse = authService.register(registerRequest);
        return ResponseEntity.ok(authResponse);
    }

    /**
     * 刷新访问令牌接口
     * 
     * 接口说明：
     * - 使用刷新令牌获取新的访问令牌
     * - 刷新令牌具有较长的有效期（默认7天）
     * - 访问令牌有效期较短（默认24小时）
     * - 刷新令牌只能使用一次，用过后会生成新的刷新令牌
     * 
     * 刷新流程：
     * 1. 验证刷新令牌的有效性和格式
     * 2. 从刷新令牌中提取用户ID
     * 3. 查询用户信息并验证用户状态
     * 4. 生成新的访问令牌和刷新令牌
     * 5. 返回新的令牌对
     * 
     * 使用场景：
     * - 访问令牌即将过期时
     * - 访问令牌已过期但刷新令牌仍有效时
     * - 用户长时间未操作后重新访问系统时
     * 
     * 安全考虑：
     * - 刷新令牌必须保密，只能存储在安全的客户端
     * - 刷新令牌只能使用一次
     * - 刷新令牌过期后需要重新登录
     * - 支持刷新令牌黑名单机制（可选）
     * 
     * 请求示例：
     * POST /api/auth/refresh-token?refreshToken=eyJhbGciOiJIUzI1NiJ9...
     * 
     * 响应示例：
     * {
     *   "token": "新的访问令牌",
     *   "refreshToken": "新的刷新令牌",
     *   "userId": 123,
     *   "username": "user123",
     *   "message": "令牌刷新成功"
     * }
     * 
     * 错误处理：
     * - 刷新令牌无效：返回401错误
     * - 刷新令牌过期：返回401错误
     * - 用户不存在或已禁用：返回401错误
     * 
     * @param refreshToken 刷新令牌字符串
     * @return ResponseEntity包装的认证响应，包含新的JWT令牌和用户信息
     */
    @PostMapping("/refresh-token")
    @Operation(summary = "刷新令牌", description = "使用刷新令牌获取新的访问令牌")
    public ResponseEntity<AuthResponse> refreshToken(@RequestParam String refreshToken) {
        AuthResponse authResponse = authService.refreshToken(refreshToken);
        return ResponseEntity.ok(authResponse);
    }

    /**
     * 用户注销接口
     * 
     * 接口说明：
     * - 将当前用户的访问令牌加入黑名单
     * - 清理用户的会话信息
     * - 需要携带有效的JWT访问令牌
     * - 注销后令牌将失效，需要重新登录
     * 
     * 注销流程：
     * 1. 从Authorization请求头中提取JWT令牌
     * 2. 验证令牌格式（必须以"Bearer "开头）
     * 3. 调用认证服务进行注销处理
     * 4. 将令牌加入黑名单
     * 5. 返回成功响应
     * 
     * 使用场景：
     * - 用户主动退出登录
     * - 切换账号时注销当前账号
     * - 安全考虑需要强制用户重新登录
     * 
     * 安全考虑：
     * - 令牌必须包含"Bearer "前缀
     * - 令牌格式错误时静默处理（不报错）
     * - 注销后的令牌无法再次使用
     * - 支持令牌黑名单机制
     * 
     * 请求示例：
     * POST /api/auth/logout
     * Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
     * 
     * 响应示例：
     * HTTP/1.1 200 OK
     * 
     * 错误处理：
     * - 令牌无效：返回200（静默处理）
     * - 令牌格式错误：返回200（静默处理）
     * - 令牌已过期：返回200（静默处理）
     * 
     * @param token Authorization请求头中的JWT令牌（格式：Bearer {token}）
     * @return ResponseEntity<Void> 空响应体，只返回状态码
     */
    @PostMapping("/logout")
    @Operation(summary = "用户注销", description = "用户注销登录")
    public ResponseEntity<Void> logout(@RequestHeader("Authorization") String token) {
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            authService.logout(token);
        }
        return ResponseEntity.ok().build();
    }

    /**
     * 修改用户密码接口
     * 
     * 接口说明：
     * - 允许用户修改自己的登录密码
     * - 需要验证旧密码的正确性
     * - 新密码和确认密码必须一致
     * - 密码修改后需要重新登录
     * 
     * 密码修改流程：
     * 1. 验证用户ID的有效性
     * 2. 验证旧密码的正确性
     * 3. 验证新密码和确认密码的一致性
     * 4. 使用BCrypt加密新密码
     * 5. 更新用户密码到数据库
     * 6. 记录密码修改日志
     * 
     * 安全考虑：
     * - 必须验证旧密码，防止未授权修改
     * - 新密码和确认密码必须完全一致
     * - 使用BCrypt进行单向加密存储
     * - 密码修改后所有令牌仍然有效（可配置）
     * 
     * 密码要求：
     * - 长度：6-20位字符
     * - 复杂度：必须包含字母和数字
     * - 不能包含空格和特殊字符（部分特殊字符允许）
     * - 不能与旧密码相同（可选验证）
     * 
     * 请求示例：
     * PUT /api/auth/change-password/123
     * Content-Type: application/json
     * {
     *   "oldPassword": "oldPassword123",
     *   "newPassword": "newPassword123",
     *   "confirmPassword": "newPassword123"
     * }
     * 
     * 响应示例：
     * HTTP/1.1 200 OK
     * 
     * 错误处理：
     * - 用户不存在：返回404错误
     * - 旧密码错误：返回400错误
     * - 新密码不一致：返回400错误
     * - 参数验证失败：返回400错误
     * 
     * @param userId 用户ID，从URL路径中获取
     * @param changePasswordRequest 密码修改请求对象，包含旧密码、新密码和确认密码
     * @return ResponseEntity<Void> 空响应体，只返回状态码
     */
    @PutMapping("/change-password/{userId}")
    @Operation(summary = "修改密码", description = "用户修改密码")
    public ResponseEntity<Void> changePassword(
            @PathVariable Long userId,
            @Valid @RequestBody ChangePasswordRequest changePasswordRequest) {
        authService.changePassword(userId, changePasswordRequest);
        return ResponseEntity.ok().build();
    }

    /**
     * 更新用户个人信息接口
     * 
     * 接口说明：
     * - 允许用户更新个人基本信息
     * - 支持选择性更新，只更新提供的字段
     * - 所有字段都是可选的，不提供的字段保持原值
     * - 更新后立即生效
     * 
     * 可更新字段：
     * - nickName：用户昵称，长度1-50位
     * - phoneNumber：手机号码，需符合手机号格式
     * - email：邮箱地址，需符合邮箱格式
     * - address：联系地址，长度不超过200位
     * - avatarUrl：头像URL，需为有效的图片链接
     * 
     * 更新策略：
     * - 选择性更新：只更新请求中提供的非空字段
     * - 空值处理：null值和空字符串不会更新对应字段
     * - 格式验证：邮箱、手机号等会进行格式验证
     * - 实时同步：更新后立即保存到数据库
     * 
     * 数据同步：
     * - 通过Feign客户端同步到用户服务
     * - 采用异步处理方式，不影响主流程
     * - 同步失败时记录错误日志，不影响更新成功
     * 
     * 请求示例：
     * PUT /api/auth/update-profile/123
     * Content-Type: application/json
     * {
     *   "nickName": "新昵称",
     *   "email": "newemail@example.com",
     *   "phoneNumber": "13900139000",
     *   "address": "北京市朝阳区xxx街道xxx号",
     *   "avatarUrl": "https://example.com/avatar.jpg"
     * }
     * 
     * 部分更新示例：
     * PUT /api/auth/update-profile/123
     * Content-Type: application/json
     * {
     *   "nickName": "只更新昵称"
     * }
     * 
     * 响应示例：
     * HTTP/1.1 200 OK
     * 
     * 错误处理：
     * - 用户不存在：返回404错误
     * - 参数格式错误：返回400错误
     * - 邮箱格式错误：返回400错误
     * - 手机号格式错误：返回400错误
     * 
     * @param userId 用户ID，从URL路径中获取
     * @param updateProfileRequest 用户资料更新请求对象，包含需要更新的字段
     * @return ResponseEntity<Void> 空响应体，只返回状态码
     */
    @PutMapping("/update-profile/{userId}")
    @Operation(summary = "更新用户信息", description = "用户更新个人信息")
    public ResponseEntity<Void> updateProfile(
            @PathVariable Long userId,
            @Valid @RequestBody UpdateProfileRequest updateProfileRequest) {
        authService.updateProfile(userId, updateProfileRequest);
        return ResponseEntity.ok().build();
    }

    /**
     * 更新用户状态接口
     * 
     * 接口说明：
     * - 更新用户的启用/禁用状态
     * - 用于管理员控制用户账户状态
     * - 状态变更立即生效
     * - 需要携带有效的JWT访问令牌
     * 
     * 使用场景：
     * - 管理员禁用违规用户账户
     * - 管理员重新启用被禁用的账户
     * - 用户服务同步用户状态变更
     * 
     * 安全考虑：
     * - 需要有效的JWT访问令牌
     * - 状态变更需要记录日志
     * - 禁用的用户无法登录系统
     * - 状态变更不影响现有令牌有效性
     * 
     * 请求示例：
     * PUT /api/auth/users/123/status
     * Content-Type: application/json
     * Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
     * 
     * {
     *   "enabled": false
     * }
     * 
     * 响应示例：
     * HTTP/1.1 200 OK
     * 
     * 错误处理：
     * - 用户不存在：返回404错误
     * - 参数格式错误：返回400错误
     * - 令牌无效：返回401错误
     * - 令牌过期：返回401错误
     * 
     * @param userId 用户ID，从URL路径中获取
     * @param request 状态更新请求，包含enabled字段
     * @return ResponseEntity<Void> 空响应体，只返回状态码
     */
    @PutMapping("/users/{userId}/status")
    @Operation(summary = "更新用户状态", description = "更新用户的启用/禁用状态，用于管理员控制用户账户")
    public ResponseEntity<Void> updateUserStatus(
            @PathVariable Long userId,
            @RequestBody Map<String, Boolean> request) {
        Boolean enabled = request.get("enabled");
        if (enabled == null) {
            return ResponseEntity.badRequest().build();
        }
        authService.updateUserStatus(userId, enabled);
        return ResponseEntity.ok().build();
    }

    /**
     * 获取用户基本信息接口
     * 
     * 接口说明：
     * - 根据用户ID获取用户基本信息
     * - 用于用户服务同步用户信息
     * - 只返回必要的用户字段，不包含敏感信息
     * - 需要携带有效的JWT访问令牌
     * 
     * 返回字段：
     * - id：用户ID
     * - username：用户名
     * - email：邮箱地址
     * - phoneNumber：手机号码
     * - nickName：用户昵称
     * - avatarUrl：头像URL
     * - address：联系地址
     * - userType：用户类型（CUSTOMER/ADMIN/MERCHANT）
     * - enabled：账户是否启用
     * - createdAt：创建时间
     * - updatedAt：更新时间
     * 
     * 使用场景：
     * - 用户服务需要同步用户信息时
     * - 其他服务需要获取用户基本信息时
     * - 用户个人中心显示基本信息时
     * 
     * 安全考虑：
     * - 需要有效的JWT访问令牌
     * - 不返回敏感信息（如密码）
     * - 只返回必要的用户字段
     * - 支持跨服务调用
     * 
     * 请求示例：
     * GET /api/auth/user/123
     * Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
     * 
     * 响应示例：
     * {
     *   "id": 123,
     *   "username": "user123",
     *   "email": "user@example.com",
     *   "phoneNumber": "13800138000",
     *   "nickName": "用户昵称",
     *   "avatarUrl": "https://example.com/avatar.jpg",
     *   "address": "北京市朝阳区xxx街道xxx号",
     *   "userType": "CUSTOMER",
     *   "enabled": true,
     *   "createdAt": "2024-01-01T00:00:00",
     *   "updatedAt": "2024-01-15T12:30:00"
     * }
     * 
     * 错误处理：
     * - 用户不存在：返回404错误
     * - 令牌无效：返回401错误
     * - 令牌过期：返回401错误
     * 
     * @param userId 用户ID，从URL路径中获取
     * @return ResponseEntity<UserInfoResponse> 用户基本信息响应
     */
    @GetMapping("/user/{userId}")
    @Operation(summary = "获取用户基本信息", description = "根据用户ID获取用户基本信息，用于服务间同步")
    public ResponseEntity<UserInfoResponse> getUserInfo(@PathVariable Long userId) {
        UserInfoResponse userInfo = authService.getUserInfo(userId);
        return ResponseEntity.ok(userInfo);
    }

    /**
     * 删除用户接口
     * 
     * 接口说明：
     * - 根据用户ID删除用户账户
     * - 用于用户服务同步用户删除操作
     * - 删除用户相关的所有认证信息
     * - 需要携带有效的JWT访问令牌
     * 
     * 删除内容：
     * - 用户基本信息
     * - 用户角色关联信息
     * - 用户的JWT令牌记录
     * - 用户的刷新令牌记录
     * 
     * 使用场景：
     * - 管理员删除用户时同步删除认证信息
     * - 用户服务需要删除用户认证数据时
     * - 系统清理无效用户数据时
     * 
     * 安全考虑：
     * - 需要有效的JWT访问令牌
     * - 操作不可恢复，需谨慎处理
     * - 删除后用户无法登录系统
     * - 支持跨服务调用
     * 
     * 请求示例：
     * DELETE /api/auth/users/123
     * Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
     * 
     * 响应示例：
     * HTTP/1.1 200 OK
     * 
     * 错误处理：
     * - 用户不存在：返回404错误
     * - 令牌无效：返回401错误
     * - 令牌过期：返回401错误
     * 
     * @param userId 用户ID，从URL路径中获取
     * @return ResponseEntity<Void> 空响应体，只返回状态码
     */
    @DeleteMapping("/users/{userId}")
    @Operation(summary = "删除用户", description = "根据用户ID删除用户认证信息，用于服务间同步")
    public ResponseEntity<Void> deleteUser(@PathVariable Long userId) {
        authService.deleteUserById(userId);
        return ResponseEntity.ok().build();
    }

    /**
     * 批量删除用户接口
     * 
     * 接口说明：
     * - 根据用户ID列表批量删除用户账户
     * - 用于用户服务同步批量用户删除操作
     * - 删除所有用户相关的认证信息
     * - 需要携带有效的JWT访问令牌
     * 
     * 删除内容：
     * - 用户基本信息列表
     * - 用户角色关联信息列表
     * - 用户的JWT令牌记录列表
     * - 用户的刷新令牌记录列表
     * 
     * 使用场景：
     * - 管理员批量删除用户时同步删除认证信息
     * - 用户服务需要批量删除用户认证数据时
     * - 系统批量清理无效用户数据时
     * 
     * 安全考虑：
     * - 需要有效的JWT访问令牌
     * - 操作不可恢复，需谨慎处理
     * - 删除后用户无法登录系统
     * - 支持跨服务调用
     * 
     * 请求示例：
     * POST /api/auth/users/batch-delete
     * Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
     * Content-Type: application/json
     * 
     * {
     *   "ids": [123, 456, 789]
     * }
     * 
     * 响应示例：
     * HTTP/1.1 200 OK
     * 
     * 错误处理：
     * - 用户不存在：返回404错误
     * - 参数格式错误：返回400错误
     * - 令牌无效：返回401错误
     * - 令牌过期：返回401错误
     * 
     * @param request 包含用户ID列表的请求体
     * @return ResponseEntity<Void> 空响应体，只返回状态码
     */
    @PostMapping("/users/batch-delete")
    @Operation(summary = "批量删除用户", description = "根据用户ID列表批量删除用户认证信息，用于服务间同步")
    public ResponseEntity<Void> batchDeleteUsers(@RequestBody Map<String, Object> request) {
        List<Long> userIds = (List<Long>) request.get("ids");
        if (userIds == null || userIds.isEmpty()) {
            return ResponseEntity.badRequest().build();
        }
        authService.batchDeleteUsers(userIds);
        return ResponseEntity.ok().build();
    }

    /**
     * 服务登录接口
     * 
     * 接口说明：
     * - 用于微服务间调用认证服务获取访问令牌
     * - 验证服务身份并返回有效的JWT令牌
     * - 支持服务间安全通信
     * 
     * 请求参数：
     * - serviceId：服务ID，标识调用方的服务名称
     * - serviceKey：服务密钥，用于验证服务身份
     * 
     * 返回字段：
     * - token：访问令牌，用于服务间API调用的认证
     * - tokenType：令牌类型，固定为"Bearer"
     * - expiresIn：令牌有效期（秒）
     * - serviceId：服务ID，返回登录成功的服务ID
     * 
     * 使用场景：
     * - 用户服务需要调用认证服务API时
     * - 订单服务需要获取用户信息时
     * - 其他微服务间需要安全通信时
     * 
     * 安全考虑：
     * - 验证服务身份的合法性
     * - 令牌具有有效期限制
     * - 服务密钥需要安全存储
     * - 支持令牌自动刷新
     * 
     * 请求示例：
     * POST /api/auth/service-login
     * Content-Type: application/json
     * 
     * {
     *   "serviceId": "user-service",
     *   "serviceKey": "service-secret-key-12345"
     * }
     * 
     * 响应示例：
     * {
     *   "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyLXNlcnZpY2UiLCJzZXJ2aWNlIjp0cnVlLCJleHAiOjE2NDk5MjAwMDB9.signature",
     *   "tokenType": "Bearer",
     *   "expiresIn": 3600,
     *   "serviceId": "user-service"
     * }
     * 
     * 错误处理：
     * - 服务ID或密钥无效：返回401错误
     * - 参数格式错误：返回400错误
     * - 服务未注册：返回403错误
     * 
     * @param request 服务登录请求，包含serviceId和serviceKey
     * @return ResponseEntity<ServiceLoginResponse> 服务登录响应，包含访问令牌
     */
    @PostMapping("/service-login")
    @Operation(summary = "服务登录", description = "微服务间调用认证服务获取访问令牌")
    public ResponseEntity<ServiceLoginResponse> serviceLogin(@RequestBody ServiceLoginRequest request) {
        ServiceLoginResponse response = authService.serviceLogin(request);
        return ResponseEntity.ok(response);
    }
}